#include "stdafx.h"
#include "ZSocketNetworkController.h"
#include "ZAsyncSocket.h"
#include "ZMessageReceiver.h"
#include "ZUtility.h"

namespace	Z	{

//------------------------------------------------------------------------------------------------------------------------
SocketNetworkController::SocketNetworkController(size_t numPooledThread)
:	mNumPooledThread(numPooledThread)
{
}

SocketNetworkController::~SocketNetworkController()
{
}

bool SocketNetworkController::start(MessageReceiver* pMessageReceiver)
{
	NetworkController::start(pMessageReceiver);

	return mIocp.create(0)
		&& mIocp.createThreadPool(this, mNumPooledThread);
}

void SocketNetworkController::cleanup()
{
	mIocp.destroyThreadPool();
	mIocp.destroy();
}

void SocketNetworkController::send(Stream* pStream, NetworkId kNetworkId)
{
	AsyncSocket* pSocket	= getSocket(kNetworkId);
	if(pSocket != nullptr)	{
		pSocket->send(pStream);
	}
}

void SocketNetworkController::processingThread()
{
	while(true)	{
		ULONG_PTR completionKey;
		DWORD bytesTransferred	= 0;
		OVERLAPPED* pOverlapped	= nullptr;
		const BOOL result	= mIocp.getCompletionStatus(&completionKey, &bytesTransferred, &pOverlapped);
		const NetworkId kNetworkId	= static_cast<NetworkId>(completionKey);
		if(!result)	{
			if(pOverlapped != nullptr)	{
				onClose(kNetworkId, false, true);
			}
			continue;
		}

		switch(completionKey)	{
			case destroy:
				return;
			case create:
				onRegisterSocket(reinterpret_cast<AsyncSocket*>(pOverlapped));
				break;
			case close:
				onClose(reinterpret_cast<NetworkId>(pOverlapped), true, true);
				break;
			default:
				if(!onIoComplete(kNetworkId, bytesTransferred, pOverlapped))	{
					onClose(kNetworkId, true, true);
				}
				break;
		}
	}
}

void SocketNetworkController::onRegisterSocket(AsyncSocket* pSocket)
{
	if(!onCreate(pSocket))	{
		onClose(pSocket, false, false);
		deletePtr(pSocket);
	}
}

bool SocketNetworkController::onIoComplete(NetworkId kNetworkId, size_t bytesTransferred, OVERLAPPED* pOverlapped)
{
	if(bytesTransferred == 0)	{
		return false;
	}
	AsyncSocket* pSocket	= getSocket(kNetworkId);
	if(pSocket == nullptr)
		return false;
	if(pSocket->isReceive(pOverlapped))	{
		return pSocket->onReceiveComplete(bytesTransferred, *mMessageReceiver);
	}
	else if(pSocket->isSend(pOverlapped))	{
		return pSocket->onSendComplete(bytesTransferred);
	}

	return false;
}

bool SocketNetworkController::onCreate(AsyncSocket* pSocket)
{
	if(!pSocket->setSendBufferSize(0))	{
		return false;
	}
	
	if(!mIocp.associate(pSocket->getHandle(), pSocket->getNetworkId()))	{
		return false;
	}
	mMessageReceiver->onConnect(pSocket->getNetworkId());
	return true;
}

bool SocketNetworkController::onClose(NetworkId kNetworkId, bool graceful, bool notify)
{
	return onClose(getSocket(kNetworkId), graceful, notify);
}

bool SocketNetworkController::onClose(AsyncSocket* pSocket, bool graceful, bool notify)
{
	if(pSocket == nullptr)
		return false;

	if(!pSocket->unreference())
		return false;

	if(!graceful)	{
		pSocket->setLinger(0);
	}
	if(notify)	{
		mMessageReceiver->onDisconnect(pSocket->getNetworkId());
	}

	return true;
}

BOOL SocketNetworkController::postCompletionStatus(ULONG_PTR completionKey, DWORD bytesTransferred, OVERLAPPED* pOverlapped)
{
	return mIocp.postCompletionStatus(completionKey, bytesTransferred, pOverlapped);
}

}